home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr23 / chansw53.zip / CHAINSAW.CPP < prev    next >
C/C++ Source or Header  |  1993-05-24  |  22KB  |  702 lines

  1. // FILE: CHAINSAW.CPP
  2. // MODULE: MAIN
  3. // PROGRAM: CHAINSAW 
  4.  
  5. // Public Domain, 5/24/93, Ted Davis
  6.  
  7. //////////////////////////////////////////////////////////////////////////////
  8. // CHAINSAW is a command line driven directory pruner.  It does not stop for
  9. // user confirmation and can, therefore, readily be used from batch files.
  10. //        It provides password protection to prevent casual prowlers from
  11. // using it to accidentally trash a disk or directory.  The complete path,
  12. // including drive, to the directory node at which the pruning is to occur
  13. // is passed in the command tail as the starting directory.
  14. // Switches are provided to allow the program to delete the files in that
  15. // directory, and to remove that directory, as well as all the subdirectories
  16. // and their contents.  Without that switch, only the subdirectories and
  17. // their contents will be removed.
  18. // Another switch allows operation on the root directory.   Other switches
  19. // control which messages are written and their destinations, operation on
  20. // network drives, changing the defaults, and changing the password.
  21. //
  22. // Version history:
  23. // α.1    -    the first working version, without most of the switches of
  24. //             later versions.  (mostly working, that is.)
  25. // α.2    -    debugged version of α.1
  26. //
  27. // ß.1    -    /f and /r switches added; comments solicited; default directory
  28. //             bug discovered.
  29. //
  30. // ß.2    -    comments incorporated, message control switches added; default
  31. //             directory on the branch to be pruned code fixed to correctly
  32. //             back up the tree toward the root as directories are removed.
  33. //             First outside testing (no problems found).
  34. //
  35. // ß.3    -    ^Break code added to allow the user to abort the program; password
  36. //             changing code added and simple test of password against a #define
  37. //             changed to compare against an encrypted password stored in the
  38. //             EXE file.
  39. //
  40. // ß.4    -    F and f switches separated to allow removal of starting directory.
  41. //             fix read-only, etc code, clean up several places; added password
  42. //             bypass feature.
  43. //
  44. // ß.5    _    Added summary at end of program, default changing, rework switches,
  45. //             and added network drive lockout.  This was a fairly extensive
  46. //             rework of the head end of the program.  Switches can now be in
  47. //             /B /D /E, /B/D/E, /BDE (or combinations, or using '-') format and
  48. //             commas, semicolons, and tabs are allowed.
  49. //
  50. // ß.5.1  -       Fixed network drive lockout to compensate for incorrect
  51. //               documentation of INT 21, Function 0x4409.
  52. //
  53. // ß.5.2  -    Bug fix (handling of empty starting directories).
  54. //
  55. // ß.5.3  -    Bug fix (reinstalling a password after removal of same).
  56. //
  57. // 5.3      -    Release Version, no function changes from the beta version.
  58. //
  59. // NOTE: when compiling this, you may get a warning that FileHandle is unused-
  60. // this warning is untrue, ignore it.
  61. //
  62. #include "chainsaw.hpp"
  63.  
  64. int cbreak;
  65. int DirList = no;
  66. int ErrorLevel = no;
  67. int FileList = no;
  68. int IsRoot = no;
  69. int KillBaseFilesOK = no;
  70. int NetworkDriveOK = no;
  71. int PasswordCheck = no;
  72. int PrintEnable = yes;
  73. int ProtectedOK = no;
  74. int RemoveStartDir = no;
  75. int RootOK = no;
  76. int SummaryFlag = yes; 
  77.  
  78. char Bad_DriveOrDir[] = "\
  79. \nThe given drive or directory does not exist or there is a problem\n\
  80. using it (door open, network drive but no /n switch, etc)... \n\
  81. CHAINSAW aborted.\n";
  82.  
  83. char Bad_NewPassword[] = "\nUnable to change password.\n\
  84. ...SEE: CHAINSAW.DOC ...CHAINSAW aborted\n";
  85.  
  86. char Bad_NewSwitches[] = "\nUnable to change default switches.\n\
  87. ...SEE: CHAINSAW.DOC ...CHAINSAW aborted\n";
  88.  
  89. char Bad_Password[] = "\nPassword incorrect or file read error\
  90. ... CHAINSAW aborted\n";
  91.  
  92. char Barf_Message[] = "\
  93. \n The calling syntax for CHAINSAW was incorrect...\n\
  94. If you do not FULLY understand the syntax and what the program does\n\
  95. you should not attempt to use it.  This program\n\
  96.           DESTROYS ENTIRE BRANCHES OF THE DIRECTORY TREE.\n\
  97. If used incorrectly, it can do untold damage.\n";
  98.  
  99. char Copyright_Message[] = "\n CHAINSAW Version xxxxx is FREEWARE, \
  100. Public Domain, 5/24/93, Ted Davis\n";
  101.  
  102. char DummyMessage[256] = "";
  103.  
  104. char GoodNewPasswordMsg[] = "\nCHAINSAW...New password installed.\n";
  105.  
  106. char Help_Message[] = "\
  107. CHAINSAW xxxxx deletes, without prompts, entire branches of a directory tree.\n\
  108. \n\
  109. Syntax: CHAINSAW {path to base directory} {password} {switches} \n\
  110. or CHAINSAW {modification switch} {password}\n\
  111. (The drive letter is required, trailing '\\' is optional.  Switches may be\n\
  112. in /bde, /b/d/e, /b /d /e, /b,/d,/e, -bde, -b-d-e, -b -d -e, etc. format, so\n\
  113. long as the first one immediately follows a '/' or '-'.)\n\
  114. \n\    There are too many switches to define all of them here, but...\n\
  115. /A restores default switches, /a changes them; b,B,d,D,e,E,l,L,m,M,o,O,s,S,\n\
  116. w,and W control the way the program writes its messages (and what messages it\n\
  117. writes).  For the rest of the listed switches, lower case enables and upper\n\
  118. case disables the feature:\n\
  119. f,F - file deletion in the base directory; g,G - base directory removal;\n\
  120. n,N - operation on network drives; p,P - deletion of read-only, hidden and\n\
  121. system files; r,R - operation on the root directory; \n\
  122. See CHAINSAW.DOC for details.\n";
  123.  
  124. char InitialDirectory[80] = "";
  125.  
  126. char Memory_Error[] = "\n Memory allocation ERROR, CHAINSAW aborted\n";
  127.  
  128. char NewSwitchesMessage[] = "\nNew default switches installed.\n";
  129.  
  130. char NullMessage[] = "";
  131.  
  132. char OldSwitchesMessage[] = "\nOriginal default switches reinstalled.\n";
  133.  
  134. char Root_NotAllowed[] = "\nUse of root directory is not enabled... \
  135. CHAINSAW aborted\n";
  136.  
  137. char Wrong_Version[] = "\nDOS 3.0 or later is required, \
  138. CHAINSAW aborted.\n";
  139.  
  140. Message_    BadDriveOrDir;
  141. Message_    BadNewPassword;
  142. Message_    BadNewSwitches;
  143. Message_    BadPassword;
  144. Message_    BarfMessage;
  145. Message_    CopyrightMessage;
  146. Message_    DirFailed;
  147. Message_    DirOK;
  148. Message_    FileFailed;
  149. Message_    FileOK;
  150. Message_    GoodNewPassword;
  151. Message_    HelpMessage;
  152. Message_    MemoryError;
  153. Message_    OldSwitches;
  154. Message_    NewSwitches;
  155. Message_    RootNotAllowed;
  156. Message_    Summary;
  157. Message_    WrongVersion;
  158.  
  159. SumData        SummaryData;
  160.  
  161. void main(int argc, char *argv[])
  162. {
  163. int LastChar = 0;
  164. int FileHandle;
  165. int i, j, ChangePasswordFlag = no;
  166. int SwitchFlag = no;
  167. int AbortFlag = no;
  168. char *argv1;
  169. char *SwitchPtr;
  170. dirkiller *dk;
  171. char DefaultSwitches[32] = "";
  172. char SwitchString[64] = ""; 
  173. char NewPasswordString[password_len] = "";
  174. char PasswordString[password_len] = "";
  175.  
  176.  
  177.     cbreak = getcbrk();            // Saves current value of break setting.
  178.     setcbrk(1);                    // Enables maximum ^Break testing.
  179.     ctrlbrk(CtrlBreakRoutine);  // Sets up ^Break testing
  180.  
  181.     // Set up message structures with default information.
  182.     BadDriveOrDir.Type            = STDERR;
  183.     BadDriveOrDir.Message        = Bad_DriveOrDir;
  184.  
  185.     BadNewPassword.Type            = STDERR;
  186.     BadNewPassword.Message        = Bad_NewPassword;
  187.  
  188.     BadNewSwitches.Type            = STDERR;
  189.     BadNewSwitches.Message        = Bad_NewSwitches;
  190.  
  191.     BadPassword.Type            = STDERR;
  192.     BadPassword.Message            = Bad_Password;
  193.  
  194.     BarfMessage.Type             = STDERR;
  195.     BarfMessage.Message         = Barf_Message;
  196.  
  197.     CopyrightMessage.Type         = STDOUT;
  198.     CopyrightMessage.Message    = Copyright_Message;
  199.     // Insert the version number into the message string.
  200.     InsertVersion(Copyright_Message + 19);
  201.  
  202.     DirFailed.Type                 = STDOUT;
  203.     DirFailed.Message             = NullMessage;
  204.  
  205.     DirOK.Type                     = NoPrint;
  206.     DirOK.Message                 = NullMessage;
  207.  
  208.     FileFailed.Type             = STDOUT;
  209.     FileFailed.Message             = NullMessage;
  210.  
  211.     FileOK.Type                 = NoPrint;
  212.     FileOK.Message                 = NullMessage;
  213.  
  214.     GoodNewPassword.Type        = STDOUT;
  215.     GoodNewPassword.Message        = GoodNewPasswordMsg;
  216.  
  217.     HelpMessage.Type             = STDOUT;
  218.     HelpMessage.Message         = Help_Message;
  219.     // Insert the version number into the message string.
  220.     InsertVersion(Help_Message + 9);
  221.  
  222.     MemoryError.Type            = STDERR;
  223.     MemoryError.Message            = Memory_Error;
  224.  
  225.     NewSwitches.Type            = STDOUT;
  226.     NewSwitches.Message            = NewSwitchesMessage;
  227.  
  228.     OldSwitches.Type            = STDOUT;
  229.     OldSwitches.Message            = OldSwitchesMessage;
  230.  
  231.     RootNotAllowed.Type            = STDERR;
  232.     RootNotAllowed.Message        = Root_NotAllowed;
  233.  
  234.     Summary.Type                = STDOUT;
  235.     Summary.Message                = NullMessage;
  236.  
  237.     WrongVersion.Type            = STDERR;
  238.     WrongVersion.Message        = Wrong_Version;
  239.     // Although some of the above is duplicated during switch scan, I put it
  240.     // all here too so that the messages will be initialized if needed before
  241.     // they are reinitialized, e.g., for the immediately following.
  242.  
  243.     // Test for DOS 3.0 or later.
  244.     if(_osmajor < 3)
  245.     {
  246.         Output(WrongVersion);
  247.         setcbrk(cbreak); exit(1);
  248.     }
  249.  
  250.     // Check password and get default switches from the .EXE file.
  251.     if((UserPassword(argv[2], argv[0], DefaultSwitches, PasswordString)) == no)
  252.     {
  253.         AbortFlag = yes;
  254.     }
  255.  
  256.     // Start building a string of switches by copying the defaults to
  257.     // the head of the string.  If the user supplied conflicting switches,
  258.     // they will follow and, therefore, override the defaults.
  259.     strcpy(SwitchString, DefaultSwitches);
  260.     // Add user switches to the string.
  261.     // First look for the first one that is a switch;
  262.     for(i = 1; i < argc; i++)
  263.     {
  264.         if((argv[i][0] == '/') || (argv[i][0] == '-')) {break;}
  265.     }
  266.     // then, using the same 'i', add everything else to the switch string.
  267.     for( ; i < argc; i++)
  268.     {
  269.         strcat(SwitchString, argv[i]);
  270.         // Fixup for the 'z' switch: spaces the switches (for 'z' it separates
  271.         // the switch and new password from the old password).
  272.         strcat(SwitchString, " ");
  273.     }
  274.     SwitchPtr = SwitchString;
  275.     // Scan the argument list for switches.
  276.     // Strip characters until a switch marker is found (to skip over
  277.     // the password, if any, and any spaces).
  278.     while(!SwitchFlag && SwitchPtr[0])
  279.     {
  280.         switch(SwitchPtr[0])
  281.         {
  282.             // '/' and '-' are equally acceptable as switch markers.
  283.             case '/':
  284.             case '-':
  285.                 SwitchFlag = yes;
  286.         }
  287.         SwitchPtr++;
  288.     }
  289.  
  290.     // Note that SwitchFlag is yes if there is a switch marker.
  291.     while(SwitchPtr[0]  && !ChangePasswordFlag)
  292.     {
  293.         // Strip off switch markers and delimiters.
  294.         switch(SwitchPtr[0])
  295.         {
  296.             case '/':
  297.             case '-':
  298.                 if((!SwitchPtr[1]) || (SwitchPtr[1] == ' '))
  299.                 {
  300.                     // If there is a marker but no switch.
  301.                     SwitchFlag = no;
  302.                 }
  303.                 break;
  304.             case ' ':
  305.             case ',':
  306.             case ';':
  307.             case '\t':
  308.             case '"':
  309.             case '\'':
  310.                 break;
  311.             case '?':
  312.             case 'h':
  313.             case 'H':
  314.                 // Help message request.
  315.                 // Display the copyright message.
  316.                 Output(CopyrightMessage);
  317.                 // Display the help message.
  318.                 Output(HelpMessage);
  319.                 setcbrk(cbreak); exit(4);    
  320.                 // If the user needs help, the program should not run.
  321.                 break;
  322.             case 'a':
  323.                 // Change the default switch settings.
  324.                 SwitchPtr++;
  325.                 for(i = 0; ((SwitchPtr[0] != ' ') && (SwitchPtr[0] != '\0')\
  326.                  && (i < 32)); i++)
  327.                 {
  328.                     DefaultSwitches[i] = SwitchPtr[0];
  329.                     SwitchPtr++;
  330.                 }
  331.                 // Null terminate the string.
  332.                 DefaultSwitches[i] = '\0';
  333.                 if(ChangePassword(PasswordString, PasswordString,\
  334.                 DefaultSwitches))
  335.                 {
  336.                     Output(BadNewSwitches);
  337.                 }
  338.                 else
  339.                 {
  340.                     Output(NewSwitches);
  341.                 }
  342.                 setcbrk(cbreak);
  343.                 exit(5);
  344.                 break;
  345.             case 'A':
  346.                 // Restore default switch settings to initial settings.
  347.                 strcpy(DefaultSwitches, DefaultSwitchString);
  348.                 if(ChangePassword(PasswordString, PasswordString,\
  349.                 DefaultSwitches))
  350.                 {
  351.                     Output(BadNewSwitches);
  352.                 }
  353.                 else
  354.                 {
  355.                     Output(OldSwitches);
  356.                 }
  357.                 setcbrk(cbreak);
  358.                 exit(5);
  359.                 break;
  360.             case 'b':
  361.                 BadDriveOrDir.Type            = STDOUT;
  362.                 BadNewPassword.Type            = STDOUT;
  363.                 BadNewSwitches.Type            = STDOUT;
  364.                 BadPassword.Type            = STDOUT;
  365.                 BarfMessage.Type             = STDOUT;
  366.                 CopyrightMessage.Type         = STDOUT;
  367.                 DirFailed.Type                 = STDOUT;
  368.                 DirOK.Type                     = STDOUT;
  369.                 FileFailed.Type             = STDOUT;
  370.                 FileOK.Type                 = STDOUT;
  371.                 GoodNewPassword.Type        = STDOUT;
  372.                 HelpMessage.Type             = STDOUT;
  373.                 MemoryError.Type            = STDOUT;
  374.                 NewSwitches.Type            = STDOUT;
  375.                 OldSwitches.Type            = STDOUT;
  376.                 RootNotAllowed.Type            = STDOUT;
  377.                 Summary.Type                = STDOUT;
  378.                 WrongVersion.Type            = STDOUT;
  379.                 break;
  380.             case 'd':
  381.                 // Enable dir only listing to STDERR.
  382.                 DirOK.Type         = STDERR;
  383.                 break;
  384.             case 'D':
  385.                 // Enable dir only listing to STDOUT
  386.                 DirOK.Type         = STDOUT;
  387.                 break;
  388.             case 'e':
  389.                 BadDriveOrDir.Type            = STDERR;
  390.                 BadNewPassword.Type            = STDERR;
  391.                 BadNewSwitches.Type            = STDERR;
  392.                 BadPassword.Type            = STDERR;
  393.                 BarfMessage.Type             = STDERR;
  394.                 CopyrightMessage.Type         = STDERR;
  395.                 DirFailed.Type                 = STDERR;
  396.                 DirOK.Type                     = STDERR;
  397.                 FileFailed.Type             = STDERR;
  398.                 FileOK.Type                 = STDERR;
  399.                 GoodNewPassword.Type        = STDERR;
  400.                 HelpMessage.Type             = STDERR;
  401.                 MemoryError.Type            = STDERR;
  402.                 NewSwitches.Type            = STDERR;
  403.                 OldSwitches.Type            = STDERR;
  404.                 RootNotAllowed.Type            = STDERR;
  405.                 Summary.Type                = STDERR;
  406.                 WrongVersion.Type            = STDERR;
  407.                 break;
  408.             case 'B':       // Default.
  409.             case 'E':        
  410.                 BadDriveOrDir.Type            = STDERR;
  411.                 BadNewPassword.Type            = STDERR;
  412.                 BadNewSwitches.Type            = STDERR;
  413.                 BadPassword.Type            = STDERR;
  414.                 BarfMessage.Type             = STDERR;
  415.                 CopyrightMessage.Type         = STDOUT;
  416.                 DirFailed.Type                 = STDOUT;
  417.                 DirOK.Type                     = NoPrint;
  418.                 FileFailed.Type             = STDOUT;
  419.                 FileOK.Type                 = NoPrint;
  420.                 GoodNewPassword.Type        = STDOUT;
  421.                 HelpMessage.Type             = STDOUT;
  422.                 MemoryError.Type            = STDERR;
  423.                 NewSwitches.Type            = STDOUT;
  424.                 OldSwitches.Type            = STDOUT;
  425.                 RootNotAllowed.Type            = STDERR;
  426.                 Summary.Type                = STDOUT;
  427.                 WrongVersion.Type            = STDERR;
  428.                 break;
  429.             case 'f':
  430.                 // Enable file deletion for the starting directory.
  431.                 KillBaseFilesOK = yes;
  432.                 break;
  433.             case 'F':        // Default (implied).
  434.                 // Disable file deletion for the starting directory.
  435.                 // Default.
  436.                 KillBaseFilesOK = no;
  437.                 break;
  438.  
  439.             case 'g':
  440.                 // Enable file deletion for the starting directory.
  441.                 KillBaseFilesOK = yes;
  442.                 // Enable removal of starting directory.
  443.                 RemoveStartDir = yes;
  444.                 break;
  445.             case 'G':        // Default.
  446.                 // Disable file deletion for the starting directory. 
  447.                 KillBaseFilesOK = no;
  448.                 // Disable removal of starting directory.
  449.                 RemoveStartDir = no;
  450.                 break;
  451.             case 'l':
  452.                 // Enable file listing to STDERR.
  453.                 FileOK.Type     = STDERR;
  454.                 break;
  455.             case 'L':
  456.                 // Enable file listing to STDOUT.
  457.                 FileOK.Type     = STDOUT;
  458.                 break;
  459.             case 'm':
  460.                 BadDriveOrDir.Type            = STDERR;
  461.                 BadNewPassword.Type            = STDERR;
  462.                 BadNewSwitches.Type            = STDERR;
  463.                 BadPassword.Type            = STDERR;
  464.                 BarfMessage.Type             = STDERR;
  465.                 DirFailed.Type                 = STDERR;
  466.                 FileFailed.Type             = STDERR;
  467.                 MemoryError.Type            = STDERR;
  468.                 RootNotAllowed.Type            = STDERR;
  469.                 WrongVersion.Type            = STDERR;
  470.                 break;
  471.             case 'M':
  472.             case 'O':
  473.                 BadDriveOrDir.Type            = STDERR;
  474.                 BadNewPassword.Type            = STDERR;
  475.                 BadNewSwitches.Type            = STDERR;
  476.                 BadPassword.Type            = STDERR;
  477.                 BarfMessage.Type             = STDERR;
  478.                 DirFailed.Type                 = STDOUT;
  479.                 FileFailed.Type             = STDOUT;
  480.                 MemoryError.Type            = STDERR;
  481.                 RootNotAllowed.Type            = STDERR;
  482.                 WrongVersion.Type            = STDERR;
  483.                 break;
  484.             case 'n':
  485.                 // Enable use on network drives.
  486.                 NetworkDriveOK = yes;
  487.                 break;
  488.             case 'N':
  489.                 // Disable use on network drives.         // Default.
  490.                 NetworkDriveOK = no;
  491.                 break;
  492.             case 'o':
  493.                 BadDriveOrDir.Type            = STDOUT;
  494.                 BadNewPassword.Type            = STDOUT;
  495.                 BadNewSwitches.Type            = STDOUT;
  496.                 BadPassword.Type            = STDOUT;
  497.                 BarfMessage.Type             = STDOUT;
  498.                 DirFailed.Type                 = STDOUT;
  499.                 FileFailed.Type             = STDOUT;
  500.                 MemoryError.Type            = STDOUT;
  501.                 RootNotAllowed.Type            = STDOUT;
  502.                 WrongVersion.Type            = STDOUT;
  503.                 break;
  504.             case 'p':
  505.                 // Allow deletion of protected files.
  506.                 ProtectedOK = yes;
  507.                 break;
  508.             case 'P':
  509.                 // Disallow deletion of protected files.    // Default.
  510.                 ProtectedOK = no;
  511.                 break;
  512.             case 'r':
  513.                 // Allow use from root directory.
  514.                 RootOK = yes;
  515.                 break;
  516.             case 'R':
  517.                 // Disallow use from root directory.        // Default.
  518.                 RootOK = no;
  519.                 break;
  520.             case 's':
  521.                 // Enable summary.      // Default.
  522.                 SummaryFlag = yes;
  523.                 break;
  524.             case 'S':
  525.                 // Disable summary.
  526.                 SummaryFlag = no;
  527.                 break;
  528.             case 'w':                   // Default.
  529.                 // Enable all messages.
  530.                 PrintEnable = yes;
  531.                 break;
  532.             case 'W':
  533.                 // Disable all messages.
  534.                 PrintEnable = no;
  535.                 break;
  536.             case 'x':
  537.                 FileFailed.Type             = NoPrint;
  538.                 break;
  539.             case 'X':
  540.                 DirFailed.Type                 = NoPrint;
  541.                 break;
  542.             case 'z':
  543.                 // New password.
  544.                 // If the program is invoked from the command line, it is
  545.                 // desirable to remove the password from view as soon as
  546.                 // possible: the lower case version of this switch does that
  547.                 // by clearing the screen.  The upper case version is for use
  548.                 // from batch files or other situations in which it is not
  549.                 // desirable to clear the screen.  The lower case version
  550.                 // falls through to the main switch code.
  551.                 clrscr();
  552.             case 'Z':
  553.                 ChangePasswordFlag = i;
  554.                 // Above line causes the scan loop to terminate.
  555.                 // Save the new password by copying it, character by character,
  556.                 // to a string variable.  Note that the new password MUST be
  557.                 // either space terminated or the last thing in the string.
  558.                 SwitchPtr++;
  559.                 for(i = 0; i < 16; i++)
  560.                 {
  561.                     if((SwitchPtr[0] == ' ')||(SwitchPtr[0] == '\0')){break;}
  562.                     NewPasswordString[i] = SwitchPtr[0];
  563.                     SwitchPtr++;
  564.                 }
  565.                 // Null terminate the string.
  566.                 NewPasswordString[i] = '\0';
  567.                 // Note that SwitchString now starts with the last character of
  568.                 // the password, and will be incremented by the last instruction
  569.                 // in the scanning loop.
  570.                 break;
  571.             default:
  572.                 SwitchFlag = no;
  573.                 break;
  574.         }
  575.         // Go to the next character.
  576.         SwitchPtr++;
  577.         // Check for bogus or missing switches.
  578.         if(!SwitchFlag)
  579.         {
  580.             Barf();    
  581.         }
  582.     }
  583.  
  584.     // Display the copyright message.
  585.     Output(CopyrightMessage);
  586.     // The actual abort for a bad password must follow the switch code since
  587.     // the help switch does not need one.  The test must precede the switch
  588.     // code in order to read the default switches.
  589.     if(AbortFlag == yes)
  590.     {       
  591.         Output(BadPassword);
  592.         setcbrk(cbreak); exit(1);
  593.     }
  594.  
  595.     if(!ChangePasswordFlag)
  596.     {
  597.         // Convert the path to upper case.
  598.         argv1 = strupr(argv[1]);
  599.  
  600.         // Convert '/' to '\'
  601.         i = 0;
  602.         while(argv[1][++i] != '\0') {if(argv[1][i] == '/'){argv[1][i] = '\\';}}
  603.         // ++i can be used since the first character cannot be '\'.
  604.  
  605.         // Test the command tail arguments for syntax and completeness.
  606.         // This is placed after the switches since /? and /z are cases in which
  607.         // these tests would fail, even though the syntax is correct.
  608.         if(argc < 2) {Barf();}  // There must be at least one argument (plus the
  609.         // program's own name as argv[0]).
  610.  
  611.         if(argv1[1] != ':')   // The path must begin with a drive (such as C:).
  612.         {    
  613.             Barf();
  614.         }
  615.  
  616.         // Strip off any trailing backslash.
  617.         // strlen() doesn't work here; it returns 0.
  618.         while(argv1[LastChar] != 0) {LastChar++;}
  619.         if(argv1[--LastChar] == '\\') {argv1[LastChar] = '\0';}
  620.  
  621.         // Test for network drive, if locked out (or nonexistent drive).
  622.         if((!NetworkDriveOK) && (NetworkDriveQuery(toupper(argv[1][0])) != 0))
  623.         {
  624.             Output(BadDriveOrDir);
  625.             setcbrk(cbreak); exit(1);
  626.         }
  627.  
  628.         // Test for the existence of the drive and directory by atempting to
  629.         // creat a file in it.
  630.         // creattemp() requires a trailing backslash, so add one first.
  631.         strcpy(InitialDirectory, argv1);
  632.         strcat(InitialDirectory, "\\");
  633.         // Attempt to creat an unique file in the directory.
  634.         if((FileHandle = creattemp(InitialDirectory, 0)) == no)
  635.         {
  636.             Output(BadDriveOrDir);
  637.             setcbrk(cbreak); exit(1);
  638.         }
  639.         else
  640.         {
  641.             // Get rid of the temp file in case base directory file deletion
  642.             // is not enabled.
  643.             unlink(InitialDirectory);
  644.         }
  645.  
  646.         // It is necessary to restore the initial directory because creattemp()
  647.         // changed it to the complete filespec of the temporary file.
  648.         strcpy(InitialDirectory, argv1);
  649.         strcat(InitialDirectory, "\\");
  650.     }
  651.  
  652.  
  653.     if(ChangePasswordFlag)
  654.     {
  655.         if((ChangePassword(NewPasswordString, argv[0], DefaultSwitches))== no)
  656.         {
  657.             Output(BadNewPassword);
  658.         }
  659.         else
  660.         {
  661.             Output(GoodNewPassword);
  662.         }
  663.         setcbrk(cbreak); 
  664.         exit(5);
  665.     }
  666.        
  667.     // Deal with the root directory case.
  668.     // Check for root directory as the starting path.
  669.     if((LastChar == 2) || ((LastChar == 3) && (argv1[3] == '\\')))
  670.     // The root is either three characters, or four with the last
  671.     // being a backslash.
  672.     {
  673.         IsRoot = yes;
  674.         if(!RootOK)
  675.         {
  676.             // If the starting directory is the root and the /r stwich 
  677.             // was not used, abort.
  678.             Output(RootNotAllowed);
  679.             setcbrk(cbreak); exit(1);
  680.         }
  681.     }
  682.  
  683.     // Initialize the summary data structure.
  684.     SummaryData.Files = SummaryData.Dirs = 0;
  685.  
  686.     // The following line is the main business of the program: it creates
  687.     // the first instance  of the object dirkiller, the constructor for which
  688.     // does the real work.
  689.     if((dk=new dirkiller(InitialDirectory,KillBaseFilesOK,RemoveStartDir))==no)
  690.     {
  691.         Output(MemoryError);
  692.         setcbrk(cbreak); exit(1);
  693.     }
  694.     else
  695.     {
  696.         delete dk;    // Free the memory allocated by "new"
  697.     }
  698.     if(SummaryFlag) {PrintSummary(SummaryData);}
  699.     setcbrk(cbreak); exit(ErrorLevel);
  700. }
  701.  
  702.